package com.example.everying.service.user.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.everying.constant.OrderConstants;
import com.example.everying.constant.PointsConstant;
import com.example.everying.context.UserContext;
import com.example.everying.mapper.user.ActivityPointsConfigMapper;
import com.example.everying.mapper.user.PointsTransactionMapper;
import com.example.everying.model.entity.user.ActivityPointsConfig;
import com.example.everying.model.entity.user.PointsTransaction;
import com.example.everying.model.vo.user.SignRewardVO;
import com.example.everying.model.vo.points.ActivityPointsConfigListVo;
import com.example.everying.model.vo.user.UserInfoVo;
import com.example.everying.service.user.ActivityPointsConfigService;
import com.example.everying.service.user.PointsAccountService;
import com.example.everying.service.user.PointsTransactionService;
import com.example.everying.utils.CampusException;
import com.example.everying.utils.Result;
import com.example.everying.utils.SignUtils;
import com.example.everying.utils.WeChatUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 活动积分配置Service实现类
 */
@Slf4j
@Service
public class ActivityPointsConfigServiceImpl extends ServiceImpl<ActivityPointsConfigMapper, ActivityPointsConfig> implements ActivityPointsConfigService {

    @Autowired
    protected ActivityPointsConfigService activityPointsConfigService;
    @Autowired
    protected PointsTransactionService transactionService;
    @Autowired
    protected PointsTransactionMapper transactionMapper;
    @Autowired
    protected PointsAccountService accountService;

    @Override
    public boolean checkActivityById(Long configId) {
        ActivityPointsConfig activityPointsConfig = baseMapper.selectById(configId);
        if (activityPointsConfig == null) {
            throw new CampusException("活动已失效", 201);
        }
        if (activityPointsConfig.getStatus() != 1) {
            throw new CampusException("活动已失效", 201);
        }
        // 判断时间有没有过期
        if (activityPointsConfig.getEndTime().isBefore(LocalDateTime.now())) {
            log.info("活动已失效 EndTime:{} New:{}", activityPointsConfig.getEndTime(), LocalDateTime.now());
            throw new CampusException("活动已失效", 201);
        }
        return true;
    }
    @Override
    public boolean checkActivityConfigById(Long configId) {
        ActivityPointsConfig activityPointsConfig = baseMapper.selectById(configId);
        if (activityPointsConfig == null) {
            return false;
        }
        if (activityPointsConfig.getStatus() != 1) {
            return false;
        }
        // 判断时间有没有过期
        if (activityPointsConfig.getEndTime().isBefore(LocalDateTime.now())) {
            log.info("活动已失效 EndTime:{} New:{}", activityPointsConfig.getEndTime(), LocalDateTime.now());
            return false;
        }
        return true;
    }

    /**
     * @param config
     * @return
     */
    @Override
    public Result<?> add(ActivityPointsConfig config) {
        UserInfoVo userInfoVo = UserContext.getUser();
        if (userInfoVo == null) {
            return Result.fail("请先登录");
        }
        if (config == null) {
            return Result.fail("参数必填");
        }
        if (config.getPoints() != null && config.getPoints() < 0) {
            return Result.fail("积分不能小于0");
        }
        if (config.getActivityName() == null || config.getActivityName().isEmpty()) {
            return Result.fail("活动名称不能为空");
        }
        if (config.getStartTime() == null && config.getEndTime() == null) {
            return Result.fail("配置时间不能为空");
        }
        if (config.getStartTime() != null && config.getStartTime().isAfter(config.getEndTime())) {
            return Result.fail("配置时间错误");
        }

        if (config.getEndTime().isBefore(LocalDateTime.now())){
            return Result.fail("配置结束时间不能小于当前时间");
        }
        if (config.getStatus() == null) {
            config.setStatus(1);
        }
        config.setCreator(userInfoVo.getId());
        config.setCreateTime(LocalDateTime.now());
        config.setUpdateTime(LocalDateTime.now());

        return baseMapper.insert(config)>0 ? Result.ok() : Result.fail();
    }

    /**
     * @param config
     * @return
     */
    @Override
    public Result<?> update(ActivityPointsConfig config) {
        UserInfoVo userInfoVo = UserContext.getUser();
        if (userInfoVo == null) {
            return Result.fail("请先登录");
        }
        if (config.getId() == null) {
            return Result.fail("未选择积分配置");
        }
        if (config.getId() <= 0) {
            return Result.fail("积分配置无效");
        }
        ActivityPointsConfig oldConfig = baseMapper.selectById(config.getId());
        if (oldConfig == null) {
            return Result.fail("未找到积分配置");
        }
        BeanUtil.copyProperties(config, oldConfig);
        oldConfig.setUpdater(userInfoVo.getId());
        oldConfig.setUpdateTime(LocalDateTime.now());
        return baseMapper.updateById(oldConfig) > 0 ? Result.ok("更新成功") : Result.fail("更新失败");
    }

    /**
     * @param pageParam
     * @param query
     * @return
     */
    @Override
    public IPage<ActivityPointsConfig> selectPage(Page<ActivityPointsConfig> pageParam, ActivityPointsConfig query) {
        if (query == null) {
            return this.page(pageParam, null);
        }
        LambdaQueryWrapper<ActivityPointsConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(query.getId() != null, ActivityPointsConfig::getId, query.getId());
        queryWrapper.eq(query.getType() != null, ActivityPointsConfig::getType, query.getType());
        queryWrapper.eq(query.getActivityName() != null, ActivityPointsConfig::getActivityName, query.getActivityName());
        queryWrapper.eq(query.getStatus() != null, ActivityPointsConfig::getStatus, query.getStatus());
        // 查询活动开始时间到结束时间
        queryWrapper.between(query.getStartTime() != null && query.getEndTime() != null,
                ActivityPointsConfig::getStartTime, query.getStartTime(), query.getEndTime());
        return this.page(pageParam, queryWrapper);
    }

    @Override
    public List<SignRewardVO> getTodayContinuousDays(String userId) {
        // 1. 查询启用的签到配置
        List<ActivityPointsConfig> configs = baseMapper.selectEnabledSignConfigs();
        if (configs.isEmpty()) {
            return new ArrayList<>();
        }
        // 2. 查询用户所有签到交易（增加 userId 过滤）
        List<PointsTransaction> transactions = transactionMapper.selectByUserId(userId);
        // 3. 计算用户当前连续签到天数（确保逻辑正确）
        int continuousDays = SignUtils.calculateContinuousDays(userId, transactions);
        // 4. 转换为前端 VO，并标记状态
        return configs.stream().map(config -> {
            SignRewardVO vo = new SignRewardVO();
            vo.setDayText("第" + config.getContinuousDays() + "天");
            vo.setPoints(config.getPoints());
            vo.setStatusDesc(config.getStatus() == 1 ? "已启用" : "已禁用");

            // 标记：是否是用户今天签到的天数（当前连续天数等于配置天数，且今日有签到）
            boolean isTodayTargetDay = config.getContinuousDays() == continuousDays;
            vo.setToday(isTodayTargetDay);
            // 优化：增加空值判断、提取常量、明确逻辑顺序
            boolean isReceived = false; // 默认为false（未领取）
            // 1. 先判断交易列表是否为空，避免空指针异常（NPE）
            if (transactions != null && !transactions.isEmpty()) {
                LocalDate today = LocalDate.now(); // 提取今日日期常量，避免重复计算
                // 构建目标描述关键词，比如要匹配“连续 X 天”，这里 X 是配置的连续签到天数
                String targetDesc = "连续 " + config.getContinuousDays() + " 天";
                // 计算用户达到该连续天数的目标日期（关键：确定应该领取的日期）
                LocalDate targetDate = calculateTargetDate(continuousDays, config.getContinuousDays(), today);
                isReceived = transactions.stream()
                        //过滤出当前用户的交易
                        .filter(t -> t.getUserId().equals(userId))
                        // 过滤出交易描述不为 null 的交易（避免 description 为 null 导致的 NPE）
                        .filter(t -> t.getDescription() != null && t.getActivityType().contains("2"))
                        .anyMatch(t -> t.getCreateTime() != null && t.getCreateTime().toLocalDate().equals(targetDate));

                vo.setReceived(isReceived);
            } else {
                vo.setReceived(false);
            }
            vo.setReceived(isReceived);

            return vo;
        }).collect(Collectors.toList());
    }

    private LocalDate calculateTargetDate(int currentContinuousDays, int configDays, LocalDate today) {
        // 情况1：当前连续天数等于配置天数 → 目标日期是今天（今天达标）
        if (currentContinuousDays == configDays) {
            return today;
        }
        // 情况2：当前连续天数超过配置天数 → 目标日期是（今天 - (当前天数 - 配置天数)天）
        else if (currentContinuousDays > configDays) {
            return today.minusDays(currentContinuousDays - configDays);
        }
        // 情况3：当前连续天数未达到配置天数 → 目标日期为null（尚未达标，无需判断）
        else {
            return null;
        }
    }

    @Override
    public ActivityPointsConfig getRewardConfigByType(String everydayUserPublishPoints) {
        return baseMapper.selectByType(everydayUserPublishPoints);
    }

    @Override
    public Result<?> getCarouselImage() {
        LambdaQueryWrapper<ActivityPointsConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNotNull(ActivityPointsConfig::getImageUrl);
        queryWrapper.isNotNull(ActivityPointsConfig::getH5Url);
        queryWrapper.eq(ActivityPointsConfig::getImageStatus, 1);
        return Result.ok(baseMapper.selectList(queryWrapper));
    }

    /**
     * @param uid
     * @return
     */
    @Override
    public List<ActivityPointsConfigListVo> selectActivityList(String uid) {
        List<ActivityPointsConfigListVo> list =  baseMapper.selectActivityListByUid(uid);
        return list;
    }

    @Override
    @Transactional
    public void cleanExpiredPoints() {
        LambdaQueryWrapper<ActivityPointsConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ActivityPointsConfig::getActivityName, "用户注册奖励积分");
        queryWrapper.eq(ActivityPointsConfig::getType, PointsConstant.USER_REGISTER_POINTS);

        ActivityPointsConfig pointsConfig = baseMapper.selectOne(queryWrapper);

        List<PointsTransaction> expiredPoints = transactionMapper.selectExpiredPoints(pointsConfig.getContinuousDays());

        if (expiredPoints == null || expiredPoints.isEmpty()) {
            return;
        }
        expiredPoints.forEach(points -> {
            String uid = points.getUserId();
            // 减去过期积分
            accountService.minusPoints(uid, points.getPointsChange(), "积分过期");
        });
    }


    /**
     * 处理用户签到奖励
     * @param userId 用户 ID
     * @param continuousDays 当前连续签到天数
     * @return 奖励结果（成功/失败）
     */
    @Transactional
    public boolean handleSignReward(String userId, int continuousDays) {
        // 1. 查询匹配的活动配置（如类型为签到、连续天数匹配）
        List<ActivityPointsConfig> configs = activityPointsConfigService.lambdaQuery()
                .eq(ActivityPointsConfig::getType, PointsConstant.SIGN_USER_PUBLISH_POINTS) // 签到活动
                .eq(ActivityPointsConfig::getContinuousDays, continuousDays)
                .eq(ActivityPointsConfig::getStatus, 1) // 启用中
                .le(ActivityPointsConfig::getStartTime, LocalDateTime.now()) // 活动已开始
                .ge(ActivityPointsConfig::getEndTime, LocalDateTime.now()) // 活动未结束
                .list();

        if (configs.isEmpty()) {
            // 无匹配活动配置，不发放奖励
            return false;
        }

        // 2. 发放积分（遍历配置，支持多奖励）
        for (ActivityPointsConfig config : configs) {
            int points = config.getPoints();
            String desc = String.format("签到奖励（连续 %d 天）", continuousDays);

            // 3. 更新积分账户
            boolean success = accountService.updatePoints(userId, points);
            if (!success) {
                // 积分更新失败（乐观锁冲突等），回滚事务
                return false;
            }

            QueryWrapper<PointsTransaction> po = new QueryWrapper<>();
            po.eq("user_id", userId);
            po.eq("activity_type", config.getType());
            po.eq("activity_type", config.getType());
            po.eq("create_time", LocalDate.now());
            if (transactionService.count(po) > 0) {
                // 存在相同描述的流水，说明已经处理过该签到奖励，不重复处理
                return false;
            }

            // 4. 记录积分流水
            PointsTransaction transaction = new PointsTransaction();
            transaction.setUserId(userId); // 假设 userId 是字符串转 Long
            transaction.setTransactionNo(WeChatUtil.generateOrderTradeNumber(OrderConstants.TRANSACTION_TYPE_PREFIX_POINTS));
            transaction.setPointsChange(points);
            transaction.setTransactionType(1); // 1-签到奖励
            transaction.setActivityType(config.getType());
            transaction.setStatus(1); // 1-成功
            transaction.setDescription(desc);
            transaction.setCreateTime(LocalDateTime.now());
            transactionService.save(transaction);
        }

        return true;
    }

}
